home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / UTILITY / NANSI33.ARJ / RAW.C < prev    next >
C/C++ Source or Header  |  1991-11-29  |  8KB  |  227 lines

  1. /*--- raw.c --------------------------------------------------------------
  2.  MS-DOS routines to set and reset raw mode, enable or disable break checking,
  3.  and check for characters on stdin.
  4.  Written by Dan Kegel (dank@moc.jpl.nasa.gov).  Enjoy.
  5.  $Log:    raw.c $
  6.  * Revision 1.5  91/11/29  14:35:28  dan_kegel
  7.  * Changed name of function to not clash with Turbo C fn of same name.
  8.  * Turbo's getchar() still annoyingly ignores Enter when in RAW mode;
  9.  * Turbo C users should use getch() rather than getchar().  Blech.
  10.  * 
  11.  * Revision 1.4  91/11/29  14:31:30  dan_kegel
  12.  * Added call to setmode to avoid ^Z returning EOF forever.
  13.  * 
  14.  * Revision 1.3  90/07/14  09:02:03  dan_kegel
  15.  * Added raw_set_stdio(), which should make it easy to use RAW mode.
  16.  * 
  17.  * Revision 1.2  90/07/09  23:18:15  dan_kegel
  18.  * Compiles with /w3 now.
  19.  * 
  20.  * Revision 1.1  90/07/09  23:11:13  dan_kegel
  21.  * Initial revision
  22.  * 
  23.  
  24.  QUICK SUMMARY:
  25.  
  26.  For fast screen output, call
  27.     raw_set_stdio(1);
  28.  at the beginning of your program, and 
  29.     raw_set_stdio(0);
  30.  at the end, and use getchar() to grab keystrokes from the keyboard.
  31.  Your screen updates will be much faster (assuming you use stdout, and
  32.  have installed NANSI.SYS or FANSI-CONSOLE), and
  33.  getchar() will treat Backspace, Enter, ^S, ^C, ^P, and ESC as normal
  34.  keystrokes rather than as editing characters.
  35.  
  36.  DETAILS and extra goodies:
  37.  
  38.  To maximize display speed, applications should set the stdout device to 
  39.  raw mode when they start up, and clear it when they exit or start up a
  40.  subshell.
  41.  It is the device associated with a file handle that has a RAW mode, not
  42.  the file handle itself.  Thus, if stdin and stdout both refer to CON:,
  43.  raw_get(fileno(stdin)) will always equal raw_get(fileno(stdout)).
  44.  
  45.  The stdin device should not be in RAW mode during normal operation 
  46.  because this disables normal command-line editing.  For example,
  47.  COPY CON: NUL: will never exit if stdin is in RAW mode.
  48.  Because RAW mode is dangerous, applications that use it should prevent
  49.  DOS from checking for Control-C or Control-Break.  This can be done by
  50.  calling break_set(0).
  51.  
  52.  To check for an input char without waiting, call raw_kbhit().
  53.  Be sure to turn off break checking before you call, unless you want
  54.  the user to be able to break out of your program!
  55.  
  56.  To use getchar() while the console is in RAW mode, you must first disable
  57.  input buffering by executing
  58.     setbuf(stdin, NULL);
  59.  or else getchar() will simply hang.
  60.  When stdin is in RAW mode, getchar() will not check for control-C,
  61.  control-S, or control-P; it will also not echo.  
  62.  (The ideas here are all UNIX-compatible, but the following code would
  63.   need changes to compile under UNIX.   Under UNIX, the only reason to
  64.   use RAW mode is to cause getchar() to not check for ^C, ^S, etc.)
  65.  
  66.  If you tend to do lots of single-character outputting to the screen,
  67.  you may need to use output buffering before you see any speed benefits from
  68.  RAW mode.  If you use putchar() to do your outputs, you can enable output
  69.  buffering by executing
  70.      static char stdoutbuf[BUFSIZ];
  71.     setbuf(stdout, stdoutbuf);
  72.  but then you you have to fflush(stdout) each time you want to be sure your
  73.  output has made it out of the buffer onto the screen.
  74. --------------------------------------------------------------------------*/
  75. #include <dos.h>
  76. #include <stdio.h>
  77. #include <fcntl.h>
  78. #include <io.h>
  79. #include "raw.h"
  80.  
  81. /* IOCTL GETBITS/SETBITS bits. */
  82. #define DEVICE        0x80
  83. #define RAW        0x20
  84.  
  85. /* IOCTL operations */
  86. #define GETBITS        0
  87. #define SETBITS        1
  88. #define GETINSTATUS    6
  89.  
  90. /* DOS function numbers. */
  91. #define BREAKCHECK    0x33
  92. #define IOCTL        0x44
  93.  
  94. /* A nice way to call the DOS IOCTL function */
  95. static int
  96. dos_ioctl(int handle, int mode, unsigned setvalue)
  97. {
  98.     union REGS regs;
  99.  
  100.     regs.h.ah = IOCTL;
  101.     regs.h.al = (char) mode;
  102.     regs.x.bx = handle;
  103.     regs.h.dl = (char) setvalue;
  104.     regs.h.dh = 0;            /* Zero out dh */
  105.     intdos(®s, ®s);
  106.     return (regs.x.dx);
  107. }
  108.  
  109. /*--------------------------------------------------------------------------
  110.  Call this routine to determinte whether the device associated with
  111.  the given file is in RAW mode.
  112.  Returns FALSE if not in raw mode, TRUE if in raw mode.
  113.  Example: old_raw = raw_get(fileno(stdin));
  114. --------------------------------------------------------------------------*/
  115. int
  116. raw_get(fd)
  117.     int fd;
  118. {
  119.     return ( RAW == (RAW & dos_ioctl(fd, GETBITS, 0)));
  120. }
  121.  
  122. /*--------------------------------------------------------------------------
  123.  Call this routine to set or clear RAW mode for the device associated with
  124.  the given file.
  125.  Example: raw_set(fileno(stdout), TRUE);
  126. --------------------------------------------------------------------------*/
  127. void
  128. raw_set(fd, raw)
  129.     int fd;
  130.     int raw;
  131. {
  132.     int bits;
  133.     bits = dos_ioctl(fd, GETBITS, 0);
  134.     if (DEVICE & bits) {
  135.         if (raw)
  136.             bits |= RAW;
  137.         else
  138.             bits &= ~RAW;
  139.         (void) dos_ioctl(fd, SETBITS, bits);
  140.     }
  141. }
  142.  
  143. /*--------------------------------------------------------------------------
  144.  If any input is ready on stdin, return a nonzero value.
  145.  Else return zero.
  146.  This works for both input files and devices.
  147.  In RAW mode, if break checking is turned off, does not check for ^C.
  148.  (The kbhit() that comes with Microsoft C seems to always check for ^C.)
  149. ----------------------------------------------------------------------------*/
  150. int
  151. raw_kbhit()
  152. {
  153.     union REGS regs;
  154.  
  155.     regs.h.ah = IOCTL;
  156.     regs.h.al = GETINSTATUS;
  157.     regs.x.bx = fileno(stdin);
  158.     intdos(®s, ®s);
  159.     return (0xff & regs.h.al);
  160. }
  161.  
  162.  
  163. /* A nice way to call the DOS BREAKCHECK function */
  164. static int
  165. breakctl(int mode, int setvalue)
  166. {
  167.     union REGS regs;
  168.  
  169.     regs.h.ah = BREAKCHECK;
  170.     regs.h.al = (char) mode;
  171.     regs.h.dl = (char) setvalue;
  172.     intdos(®s, ®s);
  173.     return (regs.x.dx & 0xff);
  174. }
  175.  
  176. /*--------------------------------------------------------------------------
  177.  Call this routine to determine whether DOS is checking for break (Control-C)
  178.  before it executes any DOS function call.
  179.  Return value is FALSE if it only checks before console I/O function calls,
  180.  TRUE if it checks before any function call.
  181. --------------------------------------------------------------------------*/
  182. int
  183. break_get(void)
  184. {
  185.     return ( 0 != breakctl(GETBITS, 0));
  186. }
  187.  
  188. /*--------------------------------------------------------------------------
  189.  Call this routine with TRUE to tell DOS to check for break (Control-C)
  190.  before it executes any DOS function call.
  191.  Call this routine with FALSE to tell DOS to only check for break before
  192.  it executes console I/O function calls.
  193. --------------------------------------------------------------------------*/
  194. void
  195. break_set(check)
  196.     int check;
  197. {
  198.     (void) breakctl(SETBITS, check);
  199. }
  200.  
  201. /*--------------------------------------------------------------------------
  202.  One routine to set (or clear) raw mode on stdin and stdout,
  203.  clear (or restore) break checking, and turn off input buffering on stdin.
  204.  This is the most common configuration; under MS-DOS, since setting raw mode
  205.  on stdout sometimes sets it on stdin, it's best to set it on both & be done
  206.  with it.
  207. --------------------------------------------------------------------------*/
  208. void
  209. raw_set_stdio(raw)
  210.     int raw;    /* TRUE -> set raw mode; FALSE -> clear raw mode */
  211. {
  212.     static int was_break_checking = 0;
  213.  
  214.     raw_set(fileno(stdin), raw);
  215.     raw_set(fileno(stdout), raw);
  216.     if (raw) {
  217.         setbuf(stdin, NULL);    /* so getchar() won't hang */
  218.         setmode(fileno(stdin), O_BINARY);    /* so ^Z won't end */
  219.         was_break_checking = break_get();
  220.         break_set(0);
  221.     } else {
  222.         break_set(was_break_checking);
  223.         setmode(fileno(stdin), O_TEXT);        /* so ^Z will be EOF */
  224.     }
  225. }
  226.  
  227.